﻿using System;
using System.Collections.Generic;

namespace Toybox.SCM.Models.LiveUtilities
{
	using NicoSharp.Extensions;
	using NicoSharp.Abstracts;

	/// <summary>
	/// コメント数を管理/制限するクラス
	/// </summary>
	public class CommentCounter : AbstractNotifyObject
	{

		#region [Static]

		protected const int DEFAULT_TIME = 20;
		protected const int DEFAULT_MAX_COUNT = 10;

		#endregion [Static]


		#region Constructor

		/// <summary>
		/// コンストラクタ
		/// </summary>
		/// <param name="maxCount"></param>
		/// <param name="time"></param>
		public CommentCounter(int maxCount = DEFAULT_MAX_COUNT, int time = DEFAULT_TIME)
		{
			this.Time = time;
			this.MaxCount = maxCount;
		}

		#endregion Constructor


		#region Public Members

		/// <summary>
		/// コメント数
		/// </summary>
		public int Count
		{
			get { return this._count; }
			protected set
			{
				if (this._count == value) return;
				this._count = value;
				base.OnPropertyChanged("Count");
				base.OnPropertyChanged("RemainingCount");
			}
		}
		private int _count;

		/// <summary>
		/// コメントの最大数
		/// </summary>
		public int MaxCount
		{
			get { return this._maxCount; }
			set
			{
				if (this._maxCount == value) return;
				this._maxCount = value;
				base.OnPropertyChanged("MaxCount");
				base.OnPropertyChanged("RemainingCount");
			}
		}
		private int _maxCount;

		/// <summary>
		/// 残りのコメント数
		/// </summary>
		public int RemainingCount
		{
			get { return this.MaxCount - this.Count; }
		}

		/// <summary>
		/// コメント数として保持しておく時間
		/// </summary>
		public int Time
		{
			get { return this._time; }
			set
			{
				if (this._time == value) return;
				this._time = value;
				base.OnPropertyChanged("Time");
			}
		}
		private int _time;


		#endregion Public Members

		#region Protected Members

		protected object _lock;
		protected Queue<int> _que;

		#endregion Protected Members


		#region Public Methods

		/// <summary>
		/// キューデータ挿入
		/// </summary>
		/// <param name="count"></param>
		public void Insert(int count)
		{
			int time = DateTime.UtcNow.GetUnixTime();

			lock (_lock)
			{
				try
				{
					for (; 0 < count; count--)
						this._que.Enqueue(time);

					for (; this.Time < (time - this._que.Peek()); )
						this._que.Dequeue();

					this.Count = this._que.Count;
				}
				catch { }
			}
		}

		/// <summary>
		/// キューデータ更新
		/// </summary>
		public void Update()
		{
			int time = DateTime.UtcNow.GetUnixTime();

			lock (_lock)
			{
				try
				{
					for (; this.Time < (time - this._que.Peek()); )
						this._que.Dequeue();

					this.Count = this._que.Count;
				}
				catch { }
			}
		}

		/// <summary>
		/// キューデータクリア
		/// </summary>
		public void Clear()
		{
			lock (_lock)
			{
				this._que.Clear();
				this.Count = this._que.Count;
			}
		}

		#endregion Public Methods
		
	}
}
